<?php

/*
 * Contains useful subclasses and functions for testing.
 */

require_once('simpletest/mock_objects.php');

Mock::generate('TemplarPHP');

/**********************************************************************
 * A subclass of UnitTestCase to test TemplarPHP requests.
 *********************************************************************/
abstract class TemplarUnitTestCase extends UnitTestCase {
    protected $templar = NULL;
    protected $originalWorkingDirectory = NULL;
    protected $testEnv = array( // array of server environment test values
        'REMOTE_ADDR'     => '223.255.255.0',
        'HTTP_USER_AGENT' => 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)',
        'HTTPS'           => '',
        'HTTP_HOST'       => 'example.com'
    );
    function setUp() {
        $this->originalWorkingDirectory = getcwd();
        /* set server environment test values */
        $_SERVER['REMOTE_ADDR']     = $this->testEnv['REMOTE_ADDR'];
        $_SERVER['HTTP_USER_AGENT'] = $this->testEnv['HTTP_USER_AGENT'];
        $_SERVER['HTTPS']           = $this->testEnv['HTTPS'];
        $_SERVER['HTTP_HOST']       = $this->testEnv['HTTP_HOST'];

        $this->templar = createProxyClass('TemplarPHP');
        chdir(dirname(__FILE__) . '/temp/'); // change working directory
        $this->templar->envFileRoot = getcwd() . DIRECTORY_SEPARATOR;
    }
    function tearDown() {
        /* restore original server values */
        foreach (array_keys($this->testEnv) as $var) {
            $_SERVER[$var] = getenv($var); // getenv() gets authentic Apache vals
        }
        chdir($this->originalWorkingDirectory); // reset cwd
    }
}


/**********************************************************************
 * Subclass of TemplarUnitTestCase with $cascade proxy property
 * and TemplarPHP mock.
 *********************************************************************/
abstract class CascadeUnitTestCase extends TemplarUnitTestCase {
    protected $cascade = NULL; //
    function setUp() {
        TemplarUnitTestCase::setUp();
        $templar = &new MockTemplarPHP();
        $templar->envRemoteAddr = $_SERVER['REMOTE_ADDR'];
        $templar->envUserAgent  = $_SERVER['HTTP_USER_AGENT'];
        $templar->envScheme     = 'http';
        $templar->envHost       = $_SERVER['HTTP_HOST'];
        $templar->envScript     = $_SERVER['SCRIPT_NAME'];
        $env_root = dirname($templar->envScript);
        $env_root = rtrim($env_root, '/') . '/'; // must end with single slash?
        $templar->envWebRoot    = $env_root;
        //$env_root = realpath(basename($templar->envScript));
        //$env_root = pathinfo($env_root, PATHINFO_DIRNAME);
        //$templar->envFileRoot   = $env_root . DIRECTORY_SEPARATOR;
        $templar->envFileRoot = getcwd() . DIRECTORY_SEPARATOR; // cwd set by TemplarUnitTestCase

        $this->cascade = createProxyClass('TemplarCascadeFramework', array(&$templar));
    }
    function tearDown() {
        TemplarUnitTestCase::tearDown();
    }
}


/**********************************************************************
 * Subclass of CascadeUnitTestCase with $template proxy property
 * and TemplarPHP mock.
 *********************************************************************/
abstract class TemplateUnitTestCase extends TemplarUnitTestCase {
    protected $template = NULL; //
    function setUp() {
        TemplarUnitTestCase::setUp();
        $templar = &new MockTemplarPHP();
        $templar->envRemoteAddr = $_SERVER['REMOTE_ADDR'];
        $templar->envUserAgent  = $_SERVER['HTTP_USER_AGENT'];
        $templar->envScheme     = 'http';
        $templar->envHost       = $_SERVER['HTTP_HOST'];
        $templar->envScript     = $_SERVER['SCRIPT_NAME'];
        $env_root = dirname($templar->envScript);
        $env_root = rtrim($env_root, '/') . '/'; // must end with single slash?
        $templar->envWebRoot    = $env_root;
        //$env_root = realpath(basename($templar->envScript));
        //$env_root = pathinfo($env_root, PATHINFO_DIRNAME);
        //$templar->envFileRoot   = $env_root . DIRECTORY_SEPARATOR;
        $templar->envFileRoot = getcwd() . DIRECTORY_SEPARATOR; // cwd set by TemplarUnitTestCase

        $this->template = createProxyClass('TemplarTemplateEngine', array(&$templar));
    }
    function tearDown() {
        TemplarUnitTestCase::tearDown();
    }
}



/**
 * Create proxy of given class. Proxy allows to test of protected class methods
 * @param string $superClassName
 * @param array|null $constructorArgs parameters for contructor
 * @return object
 *
 * From -
 * http://www.frontalaufprall.com/2007/11/16/testing-protected-methods-in-unit-tests/
 */
function createProxyClass($orig_class_name, $args=NULL) {
    $proxy_class_name = $orig_class_name . 'Proxy';
    if (!class_exists($proxy_class_name, false)) {
        $class = 'class '.$proxy_class_name.' extends '.$orig_class_name.' {
                public function __call($method, $args) {
                    if(!method_exists($this,$method)) {
                        throw new Exception("Method \'$method\' in class ".get_class($this)." does not exist");
                    }
                    $callback = array($this, $method);
                    return call_user_func_array($callback,  $args);
                }
                public function __get($property) {
                    return $this->$property;
                }
                public function __set($property, $value) {
                    $this->$property = $value;
                }
            }';
        eval($class);
    }
    /* if constructor has arguments, create with reflection class */
    if (!empty($args)) {
        $class = new ReflectionClass($proxy_class_name);
        $instance = $class->newInstanceArgs($args);
    } else {
        $instance = new $proxy_class_name();
    }
    return $instance;
}

?>
